首页
← 第 7 章 QoS 服务质量
第 8 章 事务排序
第 9 章 DLLP 元素 →
第 8 章 事务排序

8 事务排序(Transaction Ordering)

上一章

上一章讨论了支持服务质量(Quality of Service, QoS)的相关机制,并说明如何控制穿越 PCIe 结构(fabric)的不同数据包的传输时机和带宽。这些机制包括:由应用相关软件为每个数据包分配优先级,以及在每个设备中实现可选硬件,以支持事务优先级管理。

本章

本章将讨论 PCIe 拓扑中的事务排序要求。这些规则继承自 PCI,其中许多规则源于“生产者/消费者(Producer/Consumer)”编程模型,因此本章会先介绍该模型的工作机制。原始排序规则还考虑了必须避免的潜在死锁情况。

下一章

下一章将介绍数据链路层包(Data Link Layer Packet, DLLP)。内容包括 DLLP 的用途、格式、数据包类型定义以及相关字段的细节。DLLP 可用于支持 ACK/NAK 协议、电源管理、流量控制机制,也可用于厂商自定义用途。

8.1 介绍(Introduction)

和其他协议一样,对于同时在 PCIe 结构中传输、且具有相同流量类别(Traffic Class, TC)的事务,PCI Express 会施加排序规则。具有不同 TC 的事务之间不存在排序关系。对相同 TC 的事务指定排序规则,主要原因包括:

  • 维持与传统总线(legacy bus)的兼容性,例如 PCI、PCI-X 和 AGP。
  • 确保事务完成具有确定性(deterministic),并按照程序员预期的顺序完成。
  • 避免死锁(deadlock)情况。
  • 通过最小化读取延迟并管理读写顺序,最大化性能和吞吐量。

具体的 PCI/PCIe 事务排序实现基于以下特性:

  1. 生产者/消费者编程模型(Producer/Consumer programming model),这是基本排序规则的基础。
  2. 宽松排序(Relaxed Ordering, RO)选项。当请求者知道某个事务与先前事务没有任何依赖关系时,该选项允许对基本规则作出例外处理。
  3. 基于 ID 的排序(ID-Based Ordering, IDO)选项。该选项允许交换机让某个设备的请求先于另一个设备的请求前进,因为这两个设备正在执行互不相关的执行线程。
  4. 用于避免死锁并支持 PCI 传统实现的机制。

8.2 定义(Definitions)

在一个流量流中,事务排序通常有三种通用模型:

  1. 强排序(Strong Ordering):PCI Express 要求在 PCIe 结构中传输、且具有相同流量类别(TC)的事务遵循强排序规则。具有相同 TC 值的事务会映射到给定的虚拟通道(Virtual Channel, VC),因此同一 VC 内的事务也适用相同规则。因此,当多个 TC 被映射到同一个 VC 时,这些 TC 的所有事务通常会被当作一个 TC 处理,即使不同 TC 之间本身不存在排序关系。
  2. 弱排序(Weak Ordering):事务默认保持原顺序,除非重新排序有助于改善性能。由于某些事务模型(例如 Producer/Consumer 模型)存在依赖关系,强制维持事务之间的强排序关系可能会导致所有事务被阻塞。而被阻塞的事务中,很可能有一些事务与这种依赖关系无关,因此可以安全地重新排到阻塞事务之前。
  3. 宽松排序(Relaxed Ordering):事务可以被重新排序,但只能在某些受控条件下进行。它的好处是可以像弱排序模型一样提升性能,但只有在软件明确指定时才允许这样做,从而避免依赖关系问题。缺点是只有部分事务能够获得性能优化,且软件需要额外开销来为事务启用宽松排序(RO)。

8.3 简化后的排序规则(Simplified Ordering Rules)

PCIe 2.1 规范引入了一种简化版排序规则表,如表 8-1 所示。该表可以按主题划分为以下几类:

  • 生产者/消费者(Producer/Consumer)规则
  • 宽松排序(RO)规则
  • 弱排序规则
  • ID 排序规则
  • 死锁避免

后续小节会给出与各类排序模型、操作方式、基本原理、适用条件和要求相关的细节。

8.3.1 排序规则与流量类别(Ordering Rules and Traffic Classes)

PCI Express 中的排序规则适用于具有相同流量类别(TC)的事务。对于在 PCIe 结构中传输、但具有不同 TC 的事务,并没有排序要求,可以认为它们属于互不相关的应用。因此,对于不同 TC 的数据包来说,不会因为事务排序而产生性能降低。

对于共享同一个 TC 的数据包来说,当它们在 PCIe 结构中传输时,可能会经历性能降低。这是因为交换机和设备必须支持某些排序规则,而这些规则可能要求延迟某些数据包,或者允许后发数据包先于已发送数据包转发。

如第 7 章“服务质量(Quality of Service, QoS)”所述,具有不同 TC 的事务可能被映射到同一个 VC。TC 到 VC 的映射配置决定了某个给定 TC 的数据包会映射到哪个指定 VC。尽管事务排序规则只适用于相同 TC 的数据包,但在实现上,端点设备、交换机或根复合体(Root Complex, RC)可能更容易选择将事务排序规则应用于同一 VC 内的所有数据包,即使该 VC 中可能映射了多个 TC。

显然,映射到不同 VC 的数据包之间不存在排序关系,无论它们的 TC 如何。

8.3.2 基于数据包类型的排序规则(Ordering Rules Based on Packet Type)

PCIe 规范定义的排序关系基于 TLP 类型。TLP 被分为三类:

  1. Posted TLP
  2. Completion TLP
  3. Non-Posted TLP

Posted 类型的 TLP 包括内存写请求(Memory Write Request, MWr)和消息(Message, Msg/MsgD)。Completion 类型的 TLP 包括 Cpl 和 CplD。Non-Posted 类型的 TLP 包括 MRd、IORd、IOWr、CfgRd0、CfgRd1、CfgWr0 以及 CfgWr1。

下一小节中的表 8-1 描述了事务排序规则。可以看到,该表按照上述三类 TLP 列出数据包,并定义它们之间的排序关系。

8.3.3 简化后的排序规则表(The Simplified Ordering Rules Table)

该表采用“行是否可以越过列(Row Pass Column)”的方式组织。所有排序规则都在表 8-1 之后进行总结。每条规则或每组规则都定义了相应要求。

在表 8-1 中,列 2-5 表示 PCI Express 设备先前已经发出的事务,行 A-D 表示刚刚到达的新事务。对于出站事务(outbound transaction),该表指定行 A-D 所代表的事务是否可以越过列 2-5 所代表的先前事务。表中的 “No” 表示行事务不允许越过列事务;“Yes” 表示为避免死锁,必须允许行事务越过列事务;“Yes/No” 表示行事务可以越过列事务,但并不强制要求这样做。表中各条目的含义如下。

表 8-1:简化后的排序规则表

img
  • A2a、B2a、C2a、D2a:为了执行 Producer/Consumer 模型,后到达的事务不允许越过先前的 Posted 请求。
  • A2b、D2b:如果设置了 RO,则 Posted 请求或 Read Completion 在规定条件下可以越过先前已排队的 Memory Write 或 Message 请求。
  • A2b、B2b、C2b、D2b:如果使用可选的 IDO,则只要两个事务的 Requester ID 不同,后到达的事务就允许越过先前的 Posted 请求。
  • A3、A4:Memory Write 或 Message 请求必须能够越过 Non-Posted 请求,以避免死锁。
  • A5a:Posted 请求可以越过 Completion,但不要求必须越过。
  • A5b:死锁避免场景。在 PCIe-to-PCI/PCI-X 桥中,对于从 PCIe 到 PCI 或 PCI-X 的事务,Posted 请求必须能够越过 Completion,否则可能发生死锁。
  • B3、B4、B5、C3、C4、C5:这些情况用于实现弱排序,不会带来排序相关问题的风险。
  • D3、D4:Completion 必须能够越过 Read、I/O 或 Configuration Write 请求(Non-Posted 请求),以避免死锁。
  • D5a:具有不同 Transaction ID 的 Completion 可以相互越过。
  • D5b:具有相同 Transaction ID 的 Completion 不能相互越过,必须保持原顺序。这是为了保证当单个请求返回多个 Completion 时,它们仍能保持地址递增顺序。

8.4 生产者/消费者模型(Producer/Consumer Model)

本节描述 Producer/Consumer(生产者/消费者)模型的工作方式,以及为保证该模型正确运行所需的排序规则。图 8-1 简单展示了一个示例拓扑结构。后续示例先使用该拓扑说明在正确排序规则下 Producer/Consumer 模型如何运行,然后再给出一个由于排序不当而导致模型失败的示例。

Producer/Consumer 模型是 PCI 和 PCIe 中常用的数据传递方法。该模型由图 8-1 所示的 5 个元素组成:

  • 数据的 Producer(生产者)
  • 内存数据缓冲区(Memory data buffer)
  • 用于指示数据已经由 Producer 发送的 Flag semaphore(标志信号量)
  • 数据的 Consumer(消费者)
  • 用于指示 Consumer 已经读取数据的 Status semaphore(状态信号量)

规范指出,无论这些相关元素如何排列放置,Producer/Consumer 模型都应能够正常工作。在本例中,Flag 和 Status 元素位于同一个物理设备中,但它们也可以位于不同设备中。

图 8-1:生产者/消费者拓扑示例

img

8.4.1 正确的生产者/消费者流程(Producer/Consumer Sequence - No Errors)

以下讨论请参照图 8-2。该示例假设一开始 Flag 和 Status 元素均已清零。这两个信号量在本例中位于同一个设备中。下面带序号的事件流程,以及图 8-2 所示的流程,都反映了正确排序规则下流程的第一部分。

  1. 在示例中,一个被称为 Producer(生产者)的设备会执行一个或多个 MWr 事务(Memory Write,Posted 请求),目标位置为内存(Memory)中的数据缓冲区(Data Buffer)。数据流经 Posted 缓冲区时可能会产生一定延迟。
  2. Consumer(消费者)会周期性地发起 MRd 事务(Memory Read,Non-Posted 请求)来检查 Flag 信号量,以确定数据是否已经由 Producer 发出。
  3. Flag 信号量被读取,并以 MRd Completion 的形式返回给 Consumer,用于告知 Consumer:Producer 尚未完成数据交付通知(此时 Flag = 0)。
  4. Producer 发送一个 MWr(Posted 请求),将 Flag 的值更新为 1。
  5. Consumer 再次发起步骤 2 中相同的事务(MRd,Non-Posted 请求)来读取 Flag 的值。
  6. 这一次,Consumer 读取到的 Flag 值为 1。这表示 Consumer 通过此次 MRd Completion 得知,所有数据都已经由 Producer 发送到内存中。
  7. 然后,Consumer 发起一个 MWr 事务(Posted 请求),将 Flag 信号量清零。

图 8-3 继续展示该示例的第二部分流程。

  1. Producer 现在有更多数据需要发送,它会通过发起 MRd 事务(Non-Posted 请求)的方式周期性地检查 Status 信号量。
  2. Status 信号量被 Producer 读取,并以 MRd Completion 的形式返回给 Producer,用于告知 Producer:Consumer 尚未读取内存缓冲区内容,也尚未更新 Status 信号量(此时 Status = 0)。
  3. Consumer 现在已经知道内存缓冲区中有可用数据,因此会发起一个或多个 MRd(Non-Posted 请求),从缓冲区中获取这些数据。
  4. 内存缓冲区的内容被读取并返回给 Consumer。
  5. 在完成内存到 Consumer 的数据传输后,Consumer 发起一个 MWr(Posted 请求),将 Status 信号量置为 1。
  6. Producer 再次通过发起 MRd(Non-Posted 请求)来检查 Status 信号量。
  7. Producer 设备读取 Status,此时 Status = 1。MRd Completion 返回给 Producer,从而 Producer 得知内存缓冲区中的数据已经被 Consumer 读出,因此可以继续向内存缓冲区发送数据。
  8. Producer 发起 MWr,将 Status 信号量清零。
  9. Producer 重复从步骤 1 开始的一系列事件。

图 8-2:生产者/消费者流程示例——第一部分

img

图 8-3:生产者/消费者流程示例——第二部分

img

8.4.2 出错的生产者/消费者排序(Producer/Consumer Sequence - Errors)

前面的例子在未详细讨论排序规则的情况下正确执行了 Producer/Consumer 模型,但从中也可以看出,竞争条件可能导致 Producer/Consumer 流程失败。图 8-4 展示了一个简单流程,用于说明在未执行排序规则时可能出现的多种问题之一。下列讨论请参照图 8-4。

  1. Producer 向内存缓冲区发起 MWr 事务(Posted 请求)。这里假设要写入的数据暂时被阻塞在交换机上游端口的 Posted 流控缓冲区中。
  2. Producer 发送一个 MWr 事务(Posted 请求),将 Flag 更新为 1。
  3. Consumer 发起 MRd 请求(Non-Posted 请求),检查 Flag 是否已置为 1。
  4. Flag 的内容通过 Completion 返回给 Consumer。
  5. 由于 Flag = 1,Consumer 认为数据已经从 Producer 发送到内存缓冲区,因此发起 MRd 请求来获取内存缓冲区中的数据。然而 Consumer 并不知道,由于交换机上游端口与 RC 之间链路缺少流控 Credit,数据仍暂时阻塞在交换机上游端口的 Posted 流控缓冲区中。结果,Consumer 从返回的 MRd Completion 中获取到的是内存缓冲区中的旧数据,而不是 Producer 本次发出的新数据。

这个问题可以通过拓扑结构中的虚拟 PCI 桥(Virtual PCI Bridge)所支持的排序规则来避免。在本例中,当 Consumer 执行步骤 3 和步骤 4 的 MRd 事务时,交换机上游端口处的 Virtual PCI Bridge 不能允许包含 Flag 内容的 Completion(步骤 4)先于此前的 Posted 数据被转发。这种情况对应表 8-1 中的 D2a。

图 8-4:出错的生产者/消费者流程

img

8.5 宽松排序(Relaxed Ordering)

PCI Express 支持 PCI-X 引入的宽松排序机制(Relaxed Ordering, RO)。RO 允许 Requester 与 Completer 之间路径上的交换机在某些事务重新排序能够提升性能时执行重新排序。

用于支持 Producer/Consumer 模型的排序规则可能会导致某些事务被阻塞,即使这些被阻塞的事务与任何 Producer/Consumer 事务序列都无关。为缓解这一问题,可以将某个事务的 RO 属性位置为 1,表示软件已经确认该事务与其他事务无关,因此允许它重新排序到其他事务之前。例如,如果一个 Posted 写事务由于目标缓冲区空间不足而被延迟,则所有后续事务都必须等待,直到该写事务最终解除阻塞并完成交付。如果后续某个事务被软件确认与先前事务无关,并且通过设置 RO 位表明了这一点,那么它就可以在该写事务之前前进,而不会引发依赖关系问题。

如果设备驱动支持并启用了 RO 位,设备才可以使用该位。如图 8-5 所示,RO 位位于 TLP 头部中 DW0 的 Byte 2 的 bit 5。随后,当软件请求发送一个数据包时,请求包可以按照软件指示使用该属性位。当交换机或 RC 看到某个数据包的 RO 位为 1 时,它们被允许对该数据包进行重新排序,但并不强制要求必须这样做。

图 8-5:32 位头部中的宽松排序位

img

8.5.1 RO 对 MWr 和 Message 的影响(RO Effects on MWr and Message)

交换机和 RC 必须观察事务中的 RO 位设置。MWr 和 Message 都是 Posted 写事务,都会进入同一个 Posted 缓冲区,并遵循相同的排序要求。当 RO 位被置位时,交换机和 RC 对这些事务的处理如下:

  • 交换机被允许将刚刚发出的 MWr 事务(RO = 1)重新排序到先前发出的 Posted MWr 或 Message 事务之前。类似地,刚刚发出的 Message 事务(RO = 1)也可以重新排序到先前发出的 Posted MWr 或 Message 事务之前。交换机在转发事务时必须保持 RO 位不变。PCI-X 桥会忽略 RO 位,并始终按原顺序转发写事务(在 PCI-X 中允许写事务改变顺序意义不大;如果一个写事务因某种原因被阻塞,那么后一个写事务通常也会被阻塞)。另一个区别是 PCI-X 并未定义 Message 事务。
  • RC 被允许对 Posted 写事务进行重新排序。这在 RC 中是有意义的,因为 RC 可以写入不同的内存区域:如果某一区域正忙,它可以先写入另一个区域。同样地,当 RC 接收到 RO = 1 的写事务时,可以按照任意地址顺序将各个字节写入内存。

8.5.2 RO 对 MRd 事务的影响(RO Effects on MRd Transactions)

PCI Express 中所有读事务都按拆分事务(Split Transaction)处理。当某个设备发出 RO = 1 的 MRd 请求时,Completer 会通过一个或多个拆分 Completion 事务返回 Requester 所请求的数据,并在 Completion 中使用与原请求相同的 RO 设置。在这种情况下,交换机的行为如下:

  1. 当交换机接收到 RO = 1 的 MRd 时,会按接收顺序转发该 MRd 请求,且一定不能让它重新排序到先前发出的 MWr 事务之前。这可以保证所有与读请求同方向传输的写事务都会被推到读请求之前。这是前文 Producer/Consumer 示例的一部分,软件可能依赖这种类似“刷新(flush)”的动作来保证正确运行。交换机不得修改 RO 位的值。
  2. 当 Completer 接收到 MRd 请求时,它会获取被请求的数据,然后以一个或多个 Completion 的形式发送出去,这些 Completion 都具有与原请求相同的 RO 属性。
  3. 当交换机接收到 RO = 1 的 Completion 时,可以将这些 Completion 重新排序到先前发出的、与 Completion 同方向传输的 MWr 之前。如果写事务被阻塞(例如受流控限制),Completion 就可以越过这些写事务,而无需等待写事务阻塞解除。这种情况下,RO 可以改进读操作性能。表 8-2 总结了交换机允许的宽松排序行为。

表 8-2:因宽松排序而允许重新排序的事务

img

8.6 弱排序(Weak Ordering)

当严格执行强排序规则时,可能会出现暂时的事务阻塞问题。在不违反 Producer/Consumer 编程模型的前提下,可以对强排序模型进行一定修改,以消除部分阻塞情况并提升链路效率。实现弱排序模型(Weakly-Ordered model)可以缓解这一问题。

8.6.1 事务排序与流量控制(Transaction Ordering and Flow Control)

将给定 VC 的缓冲区拆分成 Posted、Non-Posted 和 Completion 三类受流控管理的子缓冲区,其动机在于:一旦 TLP 被解析或归入各自的缓冲区,就可以简化事务排序规则的处理。事务排序处理逻辑随后只需要在这三个子缓冲区之间,或在每个子缓冲区内部应用排序规则。

由于 TLP 会被归入各自的三类子缓冲区以便处理事务排序规则,因此必须在链路两端相邻端口之间,为每个虚拟通道子缓冲区(P、NP、Cpl)定义流量控制机制。实际上,你可能还记得,对于每个 VC 中的每类子缓冲区(P、NP、Cpl)来说,其 Header(Hdr)和 Data(D)子缓冲区之间也有独立的流控机制。

8.6.2 事务暂停(Transaction Stalls)

强排序规则可能导致单个接收缓冲区满而阻塞所有事务。例如,Producer/Consumer 模型相关事务的排序要求不能改变,但与该模型无关的事务排序可以进行调整。为了改善性能,可以考虑一种弱排序方案,即对事务排序施加最低限度要求的方案。

下面的例子(图 8-6)展示了单个 VC 中沿一个方向传输时,与事务交付相关的发送和接收缓冲区。回忆一下,在同一 VC 中,每种事务类型(Posted、Non-Posted 和 Completion)都有独立的流控机制。发送缓冲区内的数字表示这些事务发出的顺序,此时 Non-Posted 接收缓冲区已经满了。

图 8-6:强排序规则导致的临时事务暂停

img

考虑下面的流程:

  1. 事务 1(MRd)是下一个要发送的事务,但此时没有足够的 Non-Posted 流控 Credit,因此它必须等待。
  2. 事务 2(Posted MWr)是紧跟事务 1 之后的待发送事务。如果执行强排序规则,MWr 就不能重新排序到先前排队的读事务之前。
  3. 这种约束也会应用于后续所有事务,结果导致它们全部暂停,直到事务 1 完成。

8.6.3 VC 缓冲区提供的优势(VC Buffers Offer an Advantage)

事务排序在虚拟通道缓冲区内进行管理。这些缓冲区按照事务类型分为 Posted、Non-Posted 和 Completion 三组,并且每组都有独立的流控管理。因此,弱排序更加有用:正如上面的例子,即使一个缓冲区已满,其他缓冲区仍可能有可用空间。

8.7 基于 ID 的排序(ID-Based Ordering, IDO)

另一种优化排序并提升性能的机会与流量流(traffic stream)的性质有关。来自不同 Requester 的数据包通常不太可能存在依赖关系。毕竟,一个设备很难仅根据排序关系判断另一个设备何时完成某些步骤,因为它们可能通过不同路径访问共享资源。考虑到这一点,PCIe 2.1 规范引入了基于 ID 的排序(ID-Based Ordering, IDO),用于提升性能。

8.7.1 解决方案(The Solution)

如果事务排序没有考虑数据包来源,性能就可能受到影响,如图 8-7 所示。在该图中,事务 1 从自己的事务源到达交换机上游端口,但当它要继续前进到 RC 时被阻塞,原因是根端口中该数据包类型对应的缓冲区已满(这会表现为流控 Credit 不足)。使用规范中的术语,来自同一个 Requester 的多个数据包称为一个 TLP 流(TLP stream)。在本例中,事务 1 所示的传输路径可能包含同一个 TLP 流中的多个 TLP。随后,事务 2 也到达同一个出口端口,并且同样被阻塞,因为它必须与事务 1 保持相对顺序。

由于这两个数据包来自不同源(不同 TLP 流),这种等待几乎可以确定是不必要的;它们之间很可能不存在依赖关系,但普通排序模型并没有考虑这一点。为了改善性能,需要另一种选项。

解决方案很简单:如果数据包不使用相同的 Requester ID(对于 Completion,则不使用相同的 Completer ID),就允许对它们进行重新排序。这种可选能力允许软件使能设备使用 IDO,交换机端口也就可以识别这些数据包属于不同的 TLP 流。这通过设置设备控制 2 寄存器(Device Control 2 Register)中的使能位来实现。

图 8-7:不同数据源之间通常没有相互依赖关系

img

8.7.2 何时使用 IDO(When to Use IDO)

规范强烈建议在安全可行的情况下同时使用 IDO 和 RO。例如,当端点只与一个实体(例如 Root Complex)直接通信时,端点对所有 TLP 使用 IDO 通常是安全的。另一方面,如果端点正在与多个代理通信,则使用 IDO 可能并不安全。

规范给出的一个失败示例是:某个设备先对内存执行 DMA 写,然后又对另一个设备中的 flag 执行 peer-to-peer 写。当第二个设备收到该 flag 后,它也向同一片内存区域发起 DMA 写。通常,这两个 DMA 操作会保持顺序;但启用 IDO 后,上游设备会将它们视为来自不同设备 ID 的流量,因此不能保证两者的顺序。类似地,对于参与控制流量(control traffic)的数据包,使用 RO 也并不安全。

对于 Completer,如果已经启用 IDO,规范建议对所有 Completion 使用 IDO,除非存在明确原因不应这样做。

8.7.3 软件控制(Software Control)

软件可以通过设置某个端口的设备控制 2 寄存器(Device Control 2 Register)中的相应位,使能该端口发出的 Request 或 Completion 使用 IDO。与 RO 类似,设备中没有能力位(capability bit)告诉软件该设备支持什么,只有使能位。因此,软件需要通过其他方式知道设备是否具备该能力。否则,即使软件设置了使能位,设备若不支持 IDO,也无法真正使用 IDO。

这些位只是允许对应类型的数据包使用 IDO,软件仍需要决定每一个单独的数据包是否设置其 IDO 位。TLP 头部中新增了一个属性位,用于指示该 TLP 是否使用 IDO,如图 8-8 所示。这也带来一个相关点:Completion 通常会继承触发它的 Request 中的所有属性位,但 IDO 不一定如此,因为 Completer 可以独立启用 IDO。换句话说,即使发起它的 Request 未使用 IDO,对应 Completion 仍然可以使用 IDO。

图 8-8:64 位头部中的 IDO 属性位

img

8.8 死锁避免(Deadlock Avoidance)

由于 PCI 总线采用延迟事务(delayed transaction),以及 PCI Express 内存读请求可能因为缺少流控 Credit 而被阻塞,因此可能产生多种死锁场景。PCI Express 排序规则中包含了这些死锁避免规则,以确保无论拓扑结构如何都不会发生死锁。遵守排序规则可以防止在出现意料之外的拓扑结构时,由边界条件引发问题(例如,两个 PCIe-to-PCI 桥跨 PCIe 结构相连)。

如需详细了解这些场景,可参考 MindShare 的《PCI System Architecture, Fourth Edition》(Addison-Wesley 出版),其中对作为 PCI Express 死锁避免排序规则基础的各种场景进行了详细解释。表 8-1 列出了与死锁避免相关的排序规则,分别是 A3、A4、D3、D4 和 A5b。注意,这 5 种情况在表中都对应 “Yes” 条目,也就是说这些越过行为是为避免死锁而必须允许的。

如果列 3 或列 4 中 Non-Posted Request 缓冲区由于缺少流控 Credit 而发生阻塞,则与行 A 相关的 Posted 请求,或与行 D 相关的 Completion,必须能够移动到列 3 或列 4 所指定的 Non-Posted Request 之前。还需要注意,A5b 中的 “Yes” 条目仅适用于 PCIe-to-PCI/PCI-X 桥。

本质上,这些死锁避免规则可以总结为:必须允许后到达的 Memory Write 请求或 Completion 越过先前到达但被阻塞的 Non-Posted 请求,否则就可能发生死锁。